<template>
  <view class="mxp-radio" :style="[cusStyle, newRadioStyle]" :class="[cusClass, newDisabled ? 'disabled' : '']">
    <view style="display: flex; align-items: center; justify-content: center; padding: 2px" @click="checkeChangeClick('icon')">
      <view class="icon-view" :style="[newIconViewStyle, iconViewStyle]">
        <view
          :style="{
            opacity: isChecked || newLoading ? 1 : 0,
            transitionDuration: newLoading ? '0s' : '0.4s',
            transitionProperty: 'color,opacity',
          }"
        >
          <view v-if="newLoading" style="transform: scale(0.8)">
            <mxp-icon :spin="true" name="jiazai" :color="newIconColor" :size="iconSize"></mxp-icon>
          </view>
          <slot v-else-if="isChecked" name="activeIcon" :checked="isChecked">
            <mxp-icon name="dui" :cusStyle="{ transform: 'scale(0.6)' }" :size="iconSize" :color="newIconColor"></mxp-icon>
          </slot>
          <slot v-else name="inactiveIcon" :checked="isChecked"></slot>
        </view>
      </view>
    </view>
    <view class="label-view" :style="[labelViewStyle]" @click="checkeChangeClick('label')">
      <slot>
        <text :style="[newLabelTextStyle, labelTextStyle]">
          {{ label }}
        </text>
      </slot>
    </view>
  </view>
</template>

<script lang="ts" setup>
  import { type CSSProperties, type PropType, computed, ref, watch } from 'vue';
  import type { $AllColorStr, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import MxpIcon from '@/mxp-ui/mxp-icon/mxp-icon.vue';
  import { publicStyeProps } from '../mxp-tool/utils/public-props';
  import { defThemeColor } from '../mxp-tool/theme/theme';
  defineOptions({
    name: 'mxp-radio',
  });
  const props = defineProps({
    /** 选中的值 (主要用于配合 mxp-radio-list 使用) */
    index: { type: Number, default: -1 },
    /** 选中的值 (主要用于配合 mxp-radio-list 使用) */
    value: { type: [Boolean, String, Number, Object, Array] as PropType<any>, default: false }, // eslint-disable-line vue/no-restricted-props
    /** 是否选中 */
    checked: { type: Boolean, default: false },
    /** 形状，square为方形，circle为圆型 */
    shape: { type: String as PropType<'button' | 'circle' | 'square'>, default: 'circle' },
    /** 是否禁用 */
    disabled: { type: Boolean, default: false },
    /** 是否加载中 */
    loading: { type: Boolean, default: false },
    /** 是否可以取消选中 */
    uncheck: { type: Boolean, default: true },
    /** 图标的大小 */
    iconSize: { type: String as PropType<$SizeUnitStr>, default: '16px' },
    /** 未选中状态下图标颜色 */
    iconColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 选中状态下图标颜色 */
    iconActiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 未选中状态的背景颜色 */
    iconBackground: { type: String as PropType<$AllColorStr>, default: 'transparent' },
    /** 选中状态下的背景颜色 */
    iconActiveBackground: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 边框颜色 */
    borderColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 选中状态下的边框颜色 */
    borderActiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 显示的提示语 */
    label: { type: String, default: '' },
    /** label字体大小 */
    labelSize: { type: String as PropType<$SizeUnitStr>, default: '14px' },
    /** 未选中状态下label的颜色 */
    labelColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 选中状态下label的颜色 */
    labelActiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 是否禁止点击提示语选中单选框 */
    labelDisabled: { type: Boolean, default: false },
    /** 图标容器的样式 */
    iconViewStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** label容器的样式 */
    labelViewStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** label 文本的样式 */
    labelTextStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** 状态改变前执行的函数(需要返回 boolean 或者 Promise<boolean>) */
    beforeChange: { type: [Function, undefined] as PropType<((index: number) => Promise<boolean> | boolean) | undefined>, default: undefined },
    ...publicStyeProps,
  });
  defineSlots<{
    /** 选中图标 */
    activeIcon: () => void;
    /** 未选中图标 */
    inactiveIcon: () => void;
    /** 主体内容 */
    default: () => void;
  }>();
  const emits = defineEmits<{
    (e: 'update:checked', state: boolean): void;
    (e: 'change', res: { value: any; checked: boolean; index: number }): void;
    (e: 'valueChange', value: any): void;
    (e: 'update:loading', state: boolean): void;
  }>();
  /** 是否加载中 */
  const newLoading = ref(props.loading);

  /** 是否禁用 */
  const newDisabled = computed<boolean>(() => Boolean(props.disabled || props.disabled));

  /** 是否选中 */
  const isChecked = ref<boolean>(props.checked);
  watch(
    () => props.checked,
    (val: boolean) => {
      isChecked.value = val;
    }
  );
  watch(
    () => props.loading,
    (val) => {
      newLoading.value = val;
    }
  );

  /** icon图标颜色 */
  const newIconColor = computed<$AllColorStr>(() =>
    isChecked.value ? props.iconActiveColor || defThemeColor.value.textLight : props.iconColor || defThemeColor.value.border
  );

  const newRadioStyle = computed<CSSProperties>(() => {
    const obj: CSSProperties = {};
    if (props.shape === 'button') {
      const iconActiveBg = props.iconActiveBackground || props.labelActiveColor || defThemeColor.value.primary;
      obj.borderColor = isChecked.value ? props.borderActiveColor || iconActiveBg : props.borderColor;
      obj.borderWidth = '1px';
      obj.borderStyle = 'solid';
      obj.padding = '6px 8px';
      obj.borderRadius = '4px';
    }
    return obj;
  });
  /** 图标容器的样式 */
  const newIconViewStyle = computed<CSSProperties>(() => {
    const iconActiveBg = props.iconActiveBackground || props.labelActiveColor || defThemeColor.value.primary;
    const obj: CSSProperties = { width: props.iconSize, height: props.iconSize, backgroundColor: isChecked.value ? iconActiveBg : props.iconBackground };
    obj.borderRadius = props.shape === 'square' ? '4px' : '9999px';
    obj.borderColor = isChecked.value ? props.borderActiveColor || iconActiveBg : props.borderColor || defThemeColor.value.border;
    obj.borderWidth = '1px';
    obj.borderStyle = 'solid';
    return obj;
  });

  const newLabelTextStyle = computed<CSSProperties>(() => {
    const labelActiveColor = props.labelActiveColor || props.iconActiveBackground || defThemeColor.value.primary;
    return {
      fontSize: props.labelSize,
      lineHeight: props.labelSize,
      color: isChecked.value ? labelActiveColor : props.labelColor || defThemeColor.value.text,
    };
  });

  /** 状态改变 */
  async function checkeChangeClick(type: 'icon' | 'label') {
    if (!newDisabled.value) {
      if (type === 'icon' || (type === 'label' && !props.labelDisabled)) {
        if (typeof props.beforeChange === 'function') {
          try {
            emits('update:loading', true);
            newLoading.value = true;
            const state = await props.beforeChange(props.index);
            newLoading.value = false;
            emits('update:loading', false);
            isChecked.value = state;
            emits('update:checked', state);
            emits('change', { value: props.value, checked: isChecked.value, index: props.index });
            emits('valueChange', isChecked.value ? props.value : undefined);
          } catch (error) {
            emits('update:loading', false);
            newLoading.value = false;
          }
        } else {
          if (!isChecked.value || (isChecked.value && props.uncheck)) {
            isChecked.value = !isChecked.value;
            emits('update:checked', isChecked.value);
            emits('change', { value: props.value, checked: isChecked.value, index: props.index });
            emits('valueChange', isChecked.value ? props.value : undefined);
          }
        }
      }
    }
  }
</script>

<style lang="scss" scoped>
  .mxp-radio {
    display: flex;
    flex-flow: row nowrap;
    align-items: center;
    justify-content: center;

    &.disabled {
      opacity: 0.6;
    }

    .icon-view {
      display: flex;
      flex-flow: row nowrap;
      align-items: center;
      justify-content: center;
      transition-duration: 0.4s;
      transition-property: border-color, background, color;
    }

    .label-view {
      display: flex;
      flex-flow: row nowrap;
      padding: 2px 0;
      margin-left: 4px;

      .label-text {
        font-size: 14px;
        transition-duration: 0.2s;
        transition-property: color;
      }
    }
  }
</style>
